﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Dataglot.Utils
{
    /// <summary>
    /// For tracing all commands sent to database.
    /// </summary>
    public class TraceSql
    {
        private TraceSource trace;

        public TraceSql()
        {
            trace = new TraceSource("Dataglot.Sql");
        }

        public TraceSource Source { get { return trace; }   }

        public void TraceSqlInfoMessageEventArgs(SqlInfoMessageEventArgs sqlInfo)
        {
            trace.TraceInformation("InfoMessage: " + sqlInfo.Source);
            trace.TraceInformation("InfoMessage: " + sqlInfo.Message);
            foreach (SqlError error in sqlInfo.Errors)
            {
                trace.TraceEvent(TraceEventType.Error, 0, "SQL Error " + error.Number + ": at line number " + error.LineNumber + " :" + error.Message);
            }
        }

        public void TraceCommand(DbCommand command)
        {
            StringBuilder sql = new StringBuilder();
            FormatCommand(command, sql);
            trace.TraceInformation(Environment.NewLine+sql.ToString());
        }

        public void FormatCommand(DbCommand command, StringBuilder sb)
        {
            if(command.CommandType == CommandType.StoredProcedure)
            {
                sb.AppendLine("EXECUTE " + command.CommandText);
            }
            else if(command.CommandType == CommandType.Text)
            {
                sb.AppendLine(command.CommandText);
            }
            else if (command.CommandType == CommandType.TableDirect)
            {
                sb.AppendLine("For table : " + command.CommandText);
            }

            foreach (DbParameter parameter in command.Parameters)
            {
                sb.Append(parameter.ParameterName);
                sb.Append(" = ");
                if (parameter.Value != null)
                {
                    sb.Append(parameter.Value.ToString());
                }
                else
                {
                    sb.Append("null (not DbNull.Value)");
                }

                sb.Append(" ; ");
            }
        }

        internal void TraceSqlException(SqlException ex, DbCommand command)
        {
            //TODO: Loop through Sql Inner exceptions and collections- also MSSQL specific properties
            trace.TraceInformation("Command failed with text of " + command.CommandText + " and message of " + ex.Message);
        }

        public void TraceDbException(DbException dbEx, DbCommand command)
        {
            trace.TraceInformation("Command failed with text of " + command.CommandText + " and message of " + dbEx.Message);
        }
    }
}
